package cn.com.chengmandian.bike.service.impl;

import cn.com.chengmandian.agent.utils.AuthUtil;
import cn.com.chengmandian.bike.dto.RentOrderDto;
import cn.com.chengmandian.bike.dto.RentOrderReletForm;
import cn.com.chengmandian.bike.model.*;
import cn.com.chengmandian.bike.mapper.EbRentOrderMapper;
import cn.com.chengmandian.bike.model.vo.RentOrderVo;
import cn.com.chengmandian.bike.service.*;
import cn.com.chengmandian.bike.utils.AliPayUtil;
import cn.com.chengmandian.bike.utils.WxPayUtil;
import cn.com.chengmandian.core.common.constants.CommonConstant;
import cn.com.chengmandian.core.common.utils.BillNoUtil;
import cn.com.chengmandian.core.redis.cache.AgentCacheService;
import cn.com.chengmandian.core.redis.service.RedisService;
import cn.com.chengmandian.core.web.exceptions.BadResponseException;
import cn.com.chengmandian.core.web.pojo.AgentInfo;
import cn.com.chengmandian.core.web.pojo.AgentUser;
import cn.com.chengmandian.core.web.pojo.AjaxResult;
import cn.com.chengmandian.core.web.utils.LocalMapUtil;
import cn.com.chengmandian.core.web.utils.SpringContextUtil;
import cn.com.chengmandian.service.bike.BikePayClient;
import cn.com.chengmandian.service.bike.IotBikeClient;
import cn.com.chengmandian.service.bike.constants.*;
import cn.com.chengmandian.service.bike.form.*;
import cn.com.chengmandian.service.bike.pojo.BikeCommandNotify;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 电单车运营-分时租赁订单 服务实现类
 * </p>
 *
 * @author AutoGenerator
 * @since 2023-07-10
 */
@Slf4j
@Service
public class EbRentOrderServiceImpl extends ServiceImpl<EbRentOrderMapper, EbRentOrder> implements IEbRentOrderService {

    @Autowired
    private RedisService redisService;
    @Autowired
    private IEbDeviceBikeService deviceBikeService;
    @Autowired
    private IEbRentPenaltyService rentPenaltyService;
    @Autowired
    private IEbOperationStationService operationStationService;
    @Autowired
    private IEbMemberPayService memberPayService;
    @Autowired
    private IEbRefundInfoService refundInfoService;
    @Autowired
    private IEbMemberWalletService memberWalletService;
    @Autowired
    private IEbMemberInfoService memberInfoService;
    @Autowired
    private IEbMessageInfoService messageInfoService;
    @Autowired
    private IEbRentComboService rentComboService;
    @Autowired
    private IEbRideCommandService rideCommandService;
    @Autowired
    private IEbMemberMoneyService memberMoneyService;
    @Autowired
    private AgentCacheService agentCacheService;
    @Autowired
    private IotBikeClient iotBikeClient;
    @Autowired
    private IEbCommonParamService paramService;

    @Autowired
    private IEbAgentInfoService agentInfoService;

    @Autowired
    private IEbPayAccountService payAccountService;

    @Autowired
    private BikePayClient payClient;

    private final static String  redisKey = "CMD:BIKE:USER:RENT:";

    @Override
    public IPage<RentOrderVo> pages(RentOrderDto dto) {
        Page<RentOrderVo> page = Page.of(dto.getPageNumber(), dto.getPageSize());
        return baseMapper.getPage(page, dto);
    }

    @Override
    public EbRentOrder getByPayId(Integer payId) {
        return this.getOne(new LambdaQueryWrapper<EbRentOrder>().eq(EbRentOrder::getPayId, payId).last("limit 0,1"));
    }

    @Override
    public RentOrderVo detail(Integer id) {
        RentOrderVo vo = baseMapper.detail(id);
        EbRentPenalty rentPenalty = rentPenaltyService.getByOrderId(vo.getId());
        vo.setRentPenalty(rentPenalty);
        if(vo.getBikeId() != null){
            EbDeviceBike deviceBike = deviceBikeService.getById(vo.getBikeId());
            vo.setDeviceBike(deviceBike);
        }
        return vo;
    }

    @Override
    public RentOrderVo getComboRunning(Integer memberId) {
        EbRentOrder ebRentOrder = this.getOne(new LambdaQueryWrapper<EbRentOrder>().eq(EbRentOrder::getStatus, RentOrderStatusEnum.RENT.getCode()).eq(EbRentOrder::getMemberId, memberId).orderByAsc(EbRentOrder::getId).last("limit 0,1"));
        if(ebRentOrder == null) return null;
        RentOrderVo vo = new RentOrderVo();
        BeanUtils.copyProperties(ebRentOrder, vo);
        if(ebRentOrder.getStartTime() != null){
            vo.setUseTime((int)DateUtil.between(ebRentOrder.getStartTime(), DateUtil.date(), DateUnit.SECOND));
        }
        if(ebRentOrder.getBikeId() != null){
            EbDeviceBike deviceBike = deviceBikeService.getById(ebRentOrder.getBikeId());
            vo.setDeviceBike(deviceBike);
        }
        if(ebRentOrder.getIsRenew().equals(RentOrderIsRenewEnum.RENT.getCode())) {
            EbRentOrder endRentOrder = this.getMemberRentEndOrder(ebRentOrder.getMemberId());
            if (endRentOrder != null) {
                vo.setOrderEndTime(endRentOrder.getEndTime());
            }else{
                vo.setOrderEndTime(ebRentOrder.getEndTime());
            }
        }else {
            vo.setOrderEndTime(ebRentOrder.getEndTime());
        }
        return vo;
    }

    @Override
    public EbRentOrder getStatusOrder(Integer memberId, Integer status) {
        return this.getOne(new LambdaQueryWrapper<EbRentOrder>().eq(EbRentOrder::getMemberId, memberId).eq(EbRentOrder::getStatus, status).orderByAsc(EbRentOrder::getId).last("limit 0,1"));
    }

    @Override
    public EbRentOrder getMemberRentEndOrder(Integer memberId) {
        return this.getOne(new LambdaQueryWrapper<EbRentOrder>().eq(EbRentOrder::getMemberId, memberId).eq(EbRentOrder::getStatus, RentOrderStatusEnum.RENT.getCode()).orderByDesc(EbRentOrder::getId).last("limit 0,1"));
    }

    @Override
    public List<EbRentOrder> getByBike(String bikeNo) {
        return this.list(new LambdaQueryWrapper<EbRentOrder>().eq(EbRentOrder::getBikeNo, bikeNo).eq(EbRentOrder::getStatus, RentOrderStatusEnum.RENT.getCode()).orderByAsc(EbRentOrder::getId));
    }

    @Override
    public EbRentOrder getComboRent(Integer memberId) {
        return this.getOne(new LambdaQueryWrapper<EbRentOrder>().in(EbRentOrder::getStatus,RentOrderStatusEnum.BIKE.getCode()).eq(EbRentOrder::getMemberId, memberId).orderByAsc(EbRentOrder::getId).last("limit 0,1"));
    }

    @Override
    public EbRentOrder createRecord(Integer memberId, Integer payId, String payNo, Integer areaId, BigDecimal money, EbRentCombo combo) {
        EbRentOrder ebRentOrder = new EbRentOrder();
        ebRentOrder.setOrderNo(BillNoUtil.getSimpleNo("RH-"));
        ebRentOrder.setAreaId(areaId);
        ebRentOrder.setMemberId(memberId);
        ebRentOrder.setComboId(combo.getId());
        ebRentOrder.setPayId(payId);
        ebRentOrder.setPayNo(payNo);
        ebRentOrder.setPayTime(DateUtil.date());
        ebRentOrder.setPayMoney(money);
        Date expireTime = DateUtil.offsetHour(DateUtil.date(), 24);
        ebRentOrder.setExpireTime(expireTime);
        ebRentOrder.setIsRenew(CommonConstant.ZERO);
        ebRentOrder.setStatus(RentOrderStatusEnum.BIKE.getCode());
        ebRentOrder.setCreateTime(DateUtil.date());
        this.save(ebRentOrder);
        return ebRentOrder;
    }

    @Override
    public void checkRentBike(EbDeviceBike deviceBike) {
        Assert.notNull(deviceBike, "车辆信息不存在");
        Assert.isTrue(deviceBike.getUseStatus().equals(BikeUseStatusEnum.IDLE.getCode()), "车辆已被使用");
        Assert.isTrue(StrUtil.isNotBlank(deviceBike.getControlNo()), "中空编号不存在");

        if(StrUtil.isNotBlank(deviceBike.getSysTagsSearch())) {
            if (deviceBike.getSysTagsSearch().indexOf(BikeSysTagEnum.OFFLINE.getCode()) != -1) {
                throw new BadResponseException("车辆暂时无法骑行，请换一辆车");
            }
            if (deviceBike.getSysTagsSearch().indexOf(BikeSysTagEnum.OUT_CONTACT.getCode()) != -1) {
                throw new BadResponseException( "车辆暂时无法骑行，请换一辆车");
            }
        }

        // 因闲置原因，需要调度
        if (deviceBike.getStatus().equals(BikeStatusEnum.WAIT_DISPATCH_STATUS.getCode()) && deviceBike.getStatusReason() != null && deviceBike.getStatusReason().equals(BikeStatusReasonEnum.IDLE_TO_DISPATCH.getCode())) {
            // 允许骑行，但不改车辆状态，等车辆下单后再改
        } else if (!deviceBike.getStatus().equals(BikeStatusEnum.USE_STATUS.getCode())) {
            throw new BadResponseException("车辆当前未投放使用");
        }

        if(!deviceBike.getIsInArea().equals(CommonConstant.ONE)){
            throw new BadResponseException("车辆当前不在运营区");
        }

        EbRentOrder ebRentOrder = this.getOne(new LambdaQueryWrapper<EbRentOrder>()
                .eq(EbRentOrder::getBikeNo, deviceBike.getBikeNo())
                .eq(EbRentOrder::getStatus, RentOrderStatusEnum.RENT.getCode())
                .last("limit 0,1"));
        Assert.isNull(ebRentOrder, "车辆已被租赁");
    }

    @Override
    @Transactional
    public void rentBike(EbRentOrder rentOrder, EbDeviceBike deviceBike, AgentUser agentUser) {
        Assert.isTrue(rentOrder.getStatus().equals(RentOrderStatusEnum.BIKE.getCode()), "当前订单已在租赁中或已完成");
        Assert.notNull(rentOrder.getComboId(), "缺少套餐id");
        // 套餐信息
        EbRentCombo rentCombo = rentComboService.getById(rentOrder.getComboId());
        Assert.notNull(rentCombo, "套餐信息不存在");
        if(rentCombo.getMixSoc() != null && rentCombo.getMixSoc() > 0){
            Assert.isTrue(deviceBike.getSoc() != null && deviceBike.getSoc() > 0 && deviceBike.getSoc() > rentCombo.getMixSoc(), "该车辆不支持租赁");
        }

        String rentRedisKey = redisKey.concat(":RENT:BIKE:").concat(rentOrder.getId().toString());
        if(redisService.hasKey(rentRedisKey)){
            throw new BadResponseException("请不要重复执行");
        }
        redisService.set(rentRedisKey, rentOrder.getId(), 3);

        LambdaUpdateWrapper<EbRentOrder> orderLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        orderLambdaUpdateWrapper.set(EbRentOrder::getBikeId, deviceBike.getId());
        orderLambdaUpdateWrapper.set(EbRentOrder::getBikeNo, deviceBike.getBikeNo());
        orderLambdaUpdateWrapper.set(EbRentOrder::getStatus, RentOrderStatusEnum.RENT.getCode());
        orderLambdaUpdateWrapper.set(EbRentOrder::getStartTime, DateUtil.date());
        orderLambdaUpdateWrapper.set(EbRentOrder::getStartLat, deviceBike.getLat());
        orderLambdaUpdateWrapper.set(EbRentOrder::getStartLng, deviceBike.getLng());

        if(deviceBike.getStationId() != null){
            EbOperationStation ebOperationStation = operationStationService.getById(deviceBike.getStationId());
            if(ebOperationStation != null) {
                orderLambdaUpdateWrapper.set(EbRentOrder::getStartStationName, ebOperationStation.getName());
                orderLambdaUpdateWrapper.set(EbRentOrder::getStartStationId, ebOperationStation.getId());
            }
        }

        Date endTime = null;
        if(rentCombo.getAmount() != null && rentCombo.getAmount() > 0) {
            if (RentComboTypeEnum.MINUTE.getCode().equals(rentCombo.getType())) {
                // 分钟
                endTime = DateUtil.offsetMinute(DateUtil.date(), rentCombo.getAmount());
            }else if(RentComboTypeEnum.HOUR.getCode().equals(rentCombo.getType())){
                // 小时
                endTime = DateUtil.offsetHour(DateUtil.date(), rentCombo.getAmount());
            }else if(RentComboTypeEnum.DAY.getCode().equals(rentCombo.getType())){
                // 天
                endTime = DateUtil.offsetDay(DateUtil.date(), rentCombo.getAmount());
            }else{
                throw new BadResponseException("套餐时间类型错误");
            }
        }
        orderLambdaUpdateWrapper.set(EbRentOrder::getEndTime, endTime);
        orderLambdaUpdateWrapper.eq(EbRentOrder::getId, rentOrder.getId());
        this.update(orderLambdaUpdateWrapper);

        deviceBikeService.update(new LambdaUpdateWrapper<EbDeviceBike>()
                .set(EbDeviceBike::getUseStatus, BikeUseStatusEnum.RIDE.getCode())
                .set(EbDeviceBike::getUsePerson, UserTypeEnum.MEMBER.getCode())
                .set(EbDeviceBike::getLastRideTime, DateUtil.date())
                .set(EbDeviceBike::getLeaveAreaTime, null) // 重置下，防止有问题
                .eq(EbDeviceBike::getId, deviceBike.getId()));
        if(deviceBike.getLockStatus() != null && deviceBike.getLockStatus().equals(CommonConstant.ZERO)) {
            // 发送开锁指令
            this.sendOpenBike(this.getById(rentOrder.getId()), agentUser, UserTypeEnum.MEMBER.getCode());
        }
    }

    @Override
    public void sendOpenBike(EbRentOrder rentOrder, AgentUser agentUser, Integer userType) {
        rideCommandService.addCommand(rentOrder, DeviceCommandEnum.OPEN_LOCK, userType,agentUser.getId(),agentUser.getName(), DateUtil.date());
    }

    @Override
    @Transactional
    public void orderReturn(EbRentOrder rentOrder, AgentUser agentUser, Integer userType) {
        this.endOrder(new RentEndOrderForm().setOrderId(rentOrder.getId()).setAgentUser(agentUser).setUserType(userType), false);
    }

    @Override
    public void orderSendCommand(Integer id, DeviceCommandEnum command, AgentUser agentUser, UserTypeEnum member) {
        EbRentOrder rentOrder = this.getById(id);
        Assert.notNull(rentOrder, "租赁订单不存在");
        Assert.isTrue(RentOrderStatusEnum.RENT.getCode().equals(rentOrder.getStatus()), "订单已结束，请前往购买租赁套餐或续租");
        Assert.notNull(rentOrder.getBikeId(), "订单缺少车辆");

        EbDeviceBike deviceBike = deviceBikeService.getById(rentOrder.getBikeId());
        Assert.notNull(deviceBike, "车辆信息不存在");
        Assert.isTrue(DeviceBikeUseStatusEnum.RIDE.getCode().equals(deviceBike.getUseStatus()), "车辆未被使用");

        String commandRedisKey = redisKey.concat(":RENT:BIKE:COMMAND:").concat(id.toString());
        if(redisService.hasKey(commandRedisKey)){
            throw new BadResponseException("请不要重复执行");
        }
        redisService.set(commandRedisKey, id, 3);
        if(command.getType().equals(DeviceCommandEnum.OPEN_LOCK.getType()) || command.getType().equals(DeviceCommandEnum.CLOSE_LOCK.getType()) || command.getType().equals(DeviceCommandEnum.STOP_LOCK.getType())){
            // 结束已发出的指令
            rideCommandService.endCommand(rideCommandService.getCommand(rentOrder.getId(), command, RideCommandStatusEnum.START, RideCommandTypeEnum.RENT));

            // 发送指令
            rideCommandService.addCommand(rentOrder,command, member.getCode(), agentUser.getId(), agentUser.getName(), DateUtil.date());
        }else {
            SendBikeCommandForm form = new SendBikeCommandForm()
                    .setAgentId(rentOrder.getAgentId())
                    .setBikeNo(rentOrder.getBikeNo())
                    .setCommand(command.getType())
                    .setUserId(agentUser.getId())
                    .setUserName(agentUser.getName())
                    .setUserType(member.getCode());
            iotBikeClient.sendBikeCommand(form);
        }
    }

    @Override
    @Transactional
    public AjaxResult reletOrder(String clientIp, RentOrderReletForm form, AgentUser agentUser, AgentInfo agentInfo) {
        EbRentCombo rentCombo = rentComboService.getById(form.getComboId());
        Assert.notNull(rentCombo, "套餐不存在");
        Assert.isTrue(rentCombo.getIsDeleted().equals(CommonConstant.ZERO), "套餐已被删除");
        Assert.isTrue(rentCombo.getIsEnabled().equals(CommonConstant.ONE), "套餐已被禁用");

        EbRentOrder rentOrder = this.getMemberRentEndOrder(agentUser.getId());
        Assert.notNull(rentOrder, "未获取到被续租订单");
        Assert.isTrue(RentOrderIsRenewEnum.CLOSE.getCode().equals(rentOrder.getIsRenew()), "订单已被续租，不能再次续租");
        Assert.isTrue(RentOrderStatusEnum.RENT.getCode().equals(rentOrder.getStatus()), "租赁订单已完成，不支持续租");

        if (form.getPayChannel().equals(PayChannelEnum.WALLET.getCode())) {
            EbMemberWallet memberWallet = memberWalletService.getMemberWallet(agentUser.getId());
            if (memberWallet.getChargeMoney().compareTo(rentCombo.getPrice()) < 0) {
                throw new BadResponseException("钱包充值余额不足");
            }
        }

        String rentRedisKey = redisKey.concat(":RELET:BIKE:").concat(agentUser.getId().toString());
        if(redisService.hasKey(rentRedisKey)){
            throw new BadResponseException("请不要重复执行");
        }
        redisService.set(rentRedisKey, rentOrder.getId(), 3);

        EbMemberInfo memberInfo = memberInfoService.getById(agentUser.getId());

        EbAgentInfo info = agentInfoService.getById(agentInfo.getId());
        if (info.getPayAccountId() != null) {
            EbPayAccount payAccount = payAccountService.getPayAccount(info.getPayAccountId(), memberInfo.getId());
            if (payAccount != null && (form.getPayChannel().equals(PayChannelEnum.WXPAY.getCode()) || form.getPayChannel().equals(PayChannelEnum.ALIPAY.getCode()))) {
                PayChannelEnum payChannel = PayChannelEnum.getByCode(form.getPayChannel());
                BikePayForm bikePayForm = new BikePayForm();
                bikePayForm.setPayBusinessType(MemberPayBusinessTypeEnum.RENT_ORDER_PAY);
                bikePayForm.setPayChannel(payChannel);
                bikePayForm.setMoney(rentCombo.getPrice());
                bikePayForm.setOpenId(StrUtil.isNotBlank(form.getOpenId()) ? form.getOpenId() : memberInfo.getOpenId());
                bikePayForm.setAlipayUserId(memberInfo.getAlipayUserId());
                bikePayForm.setAlipayOpenId(memberInfo.getAlipayOpenId());
                bikePayForm.setAreaId(agentInfo.getAreaId());
                bikePayForm.setMemberId(AuthUtil.getAgentUser().getId());
                bikePayForm.setBusinessId(rentCombo.getId());
                bikePayForm.setClientIp(clientIp);
                return payClient.pay(agentInfo.getId(), bikePayForm);
            }
        }

        String notifyUrl = "http://"+ agentInfo.getDomain()+ "/api/v1/bikeuser/notify/rent";

        EbMemberPay memberPay = memberPayService.createPay(rentCombo.getAreaId(), memberInfo.getId(), MemberPayBusinessTypeEnum.RENT_ORDER_PAY, rentCombo.getId(),
                rentCombo.getPrice(), form.getPayChannel());
        try {
            if (form.getPayChannel().equals(PayChannelEnum.WXPAY.getCode())) {
                Assert.isTrue(StrUtil.isNotBlank(agentInfo.getWxMchId()), "未开启微信支付");
                if (form.getChannelType().equals(ChannelTypeEnum.MINI.getCode())) {
                    String openId = StrUtil.isNotBlank(form.getOpenId()) ? form.getOpenId() : memberInfo.getOpenId();
                    Assert.isTrue(StrUtil.isNotBlank(openId), "缺少openid");
                    return AjaxResult.success(WxPayUtil.jsapiTransactions(
                            agentInfo.getWxMiniAppid(),
                            agentInfo.getWxMchId(),
                            openId,
                            "用户购买租赁套餐",
                            memberPay.getPayNo(),
                            memberPay.getMoney(),
                            agentInfo.getWxKeyPath(),
                            agentInfo.getWxCertPath(),
                            notifyUrl + "/wxpay/pay/relet/" + LocalMapUtil.getAgentInfo().getId() + "/" + rentOrder.getId()
                    ));
                }
            } else if (form.getPayChannel().equals(PayChannelEnum.ALIPAY.getCode())) {
                // 支付宝用户唯一标识user_id 和open_id必须有一个有值
                Assert.isTrue(StrUtil.isNotBlank(memberInfo.getAlipayUserId()) || StrUtil.isNotBlank(memberInfo.getAlipayOpenId()), "用户缺少支付宝用户标识");
                return AjaxResult.success(AliPayUtil.getTradeCreateRequestParam(
                        agentInfo.getAliMiniAppid(),
                        memberInfo.getAlipayUserId(),
                        memberInfo.getAlipayOpenId(),
                        "用户购买租赁套餐",
                        memberPay.getPayNo(),
                        memberPay.getMoney(),
                        agentInfo.getAliPayPrivateKey(),
                        agentInfo.getAliPayCertPath(),
                        agentInfo.getAliPayPublicCertPath(),
                        agentInfo.getAliPayRootCertPath(),
                        notifyUrl + "/ali/pay/relet/" + LocalMapUtil.getAgentInfo().getId() + "/" + rentOrder.getId()
                ));
            } else if (form.getPayChannel().equals(PayChannelEnum.WALLET.getCode())) {
                this.reletOrderSuccess(memberPay.getPayNo(), null, rentOrder.getId());
                return AjaxResult.success("购买成功");
            }
        }catch (Exception ex){
            ex.printStackTrace();
            throw new BadResponseException(ex.getMessage());
        }
        return AjaxResult.error("不支持的支付类型");
    }

    @Override
    public void reletOrderSuccess(String payNo, String channelNo, Integer reletOrderId) {
        // 支付记录
        EbMemberPay memberPay = memberPayService.getByNo(payNo);
        Assert.isTrue(MemberPayStatusEnum.READY.getCode().equals(memberPay.getStatus()), "支付记录状态异常");
        Assert.isTrue(MemberPayBusinessTypeEnum.RENT_ORDER_PAY.getCode().equals(memberPay.getBusinessType()), "业务类型错误");

        // 套餐信息
        EbRentCombo rentCombo = rentComboService.getById(memberPay.getBusinessId());
        Assert.notNull(rentCombo, "识别不到租赁套餐");

        // 被续租的订单
        EbRentOrder reletRentOrder = this.getById(reletOrderId);
        Assert.notNull(reletOrderId, "未识别到续租订单");

        EbDeviceBike deviceBike = deviceBikeService.getById(reletRentOrder.getBikeId());

        if (memberPay.getPayChannel().equals(PayChannelEnum.WALLET.getCode())) {
            BigDecimal payChargeMoney = memberPay.getMoney();
            memberWalletService.updateBalanceForBoth(memberPay.getAreaId(), memberPay.getMemberId(), payChargeMoney, BigDecimal.ZERO, MemberMoneyBusinessTypeEnum.RIDE_COST, memberPay.getBusinessId(), MemberMoneyOperationTypeEnum.USER);
        }else if(PayChannelEnum.WXPAY.getCode().equals(memberPay.getPayChannel()) || PayChannelEnum.ALIPAY.getCode().equals(memberPay.getPayChannel())){
            memberMoneyService.createPay(memberPay.getAreaId(), memberPay.getMemberId(), MemberMoneyBusinessTypeEnum.RENT_COMBO, memberPay.getBusinessId(), MemberMoneyOperationTypeEnum.USER, memberPay.getMoney());
        }

        LambdaUpdateWrapper<EbMemberPay> memberPayLambdaUpdateWrapper = new LambdaUpdateWrapper<EbMemberPay>()
                .set(EbMemberPay::getChannelNo, channelNo)
                .set(EbMemberPay::getStatus, MemberPayStatusEnum.PAID.getCode())
                .eq(EbMemberPay::getId, memberPay.getId());

        AgentInfo agentInfo = agentCacheService.getAgent(memberPay.getAgentId().toString());
        // 手续费比例
        BigDecimal feeRatio = BigDecimal.ZERO;
        // 手续费金额
        BigDecimal feeMoney = BigDecimal.ZERO;
        // 处理微信/支付宝 支付手续费
        if(agentInfo != null) {
            if (PayChannelEnum.WXPAY.getCode().equals(memberPay.getPayChannel()) && agentInfo.getWxFeeRatio() != null) {
                feeMoney = agentInfo.getWxFeeRatio().multiply((memberPay.getMoney() == null? BigDecimal.ZERO : memberPay.getMoney())).setScale(2, BigDecimal.ROUND_HALF_UP);
                feeRatio = agentInfo.getWxFeeRatio();
            } else if (PayChannelEnum.ALIPAY.getCode().equals(memberPay.getPayChannel()) && agentInfo.getAliFeeRatio() != null) {
                feeMoney = agentInfo.getAliFeeRatio().multiply((memberPay.getMoney() == null? BigDecimal.ZERO : memberPay.getMoney())).setScale(2, BigDecimal.ROUND_HALF_UP);
                feeRatio = agentInfo.getAliFeeRatio();
            }
        }
        memberPayLambdaUpdateWrapper.set(EbMemberPay::getFeeRatio, feeRatio)
                .set(EbMemberPay::getFeeMoney, feeMoney);
        memberPayService.update(memberPayLambdaUpdateWrapper);

        this.update(new LambdaUpdateWrapper<EbRentOrder>()
                .set(EbRentOrder::getIsRenew, RentOrderIsRenewEnum.RENT.getCode())
                .eq(EbRentOrder::getId, reletRentOrder.getId()));

        Date startTime = null;
        if(DateUtil.date().getTime() >= reletRentOrder.getEndTime().getTime()){
            startTime = DateUtil.date();
        }else {
            startTime = DateUtil.offsetSecond(reletRentOrder.getEndTime(), 1);
        }

        Date endTime = null;
        if(rentCombo.getAmount() != null && rentCombo.getAmount() > 0) {
            if (RentComboTypeEnum.MINUTE.getCode().equals(rentCombo.getType())) {
                // 分钟
                endTime = DateUtil.offsetMinute(startTime, rentCombo.getAmount());
            }else if(RentComboTypeEnum.HOUR.getCode().equals(rentCombo.getType())){
                // 小时
                endTime = DateUtil.offsetHour(startTime, rentCombo.getAmount());
            }else if(RentComboTypeEnum.DAY.getCode().equals(rentCombo.getType())){
                // 天
                endTime = DateUtil.offsetDay(startTime, rentCombo.getAmount());
            }else{
                throw new BadResponseException("套餐类型错误");
            }
        }

        // 生成租赁套餐订单
        EbRentOrder rentOrder = this.createRecord(memberPay.getMemberId(), memberPay.getId(), memberPay.getPayNo(), memberPay.getAreaId(), memberPay.getMoney(), rentCombo);
        LambdaUpdateWrapper<EbRentOrder> rentOrderLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        rentOrderLambdaUpdateWrapper.set(EbRentOrder::getStartTime, startTime);
        rentOrderLambdaUpdateWrapper.set(EbRentOrder::getEndTime, endTime);
        rentOrderLambdaUpdateWrapper.set(EbRentOrder::getBikeId, deviceBike.getId());
        rentOrderLambdaUpdateWrapper.set(EbRentOrder::getBikeNo, deviceBike.getBikeNo());
        rentOrderLambdaUpdateWrapper.set(EbRentOrder::getStartLng, deviceBike.getLng());
        rentOrderLambdaUpdateWrapper.set(EbRentOrder::getStartLat, deviceBike.getLat());
        rentOrderLambdaUpdateWrapper.set(EbRentOrder::getStatus, RentOrderStatusEnum.RENT.getCode());
        rentOrderLambdaUpdateWrapper.eq(EbRentOrder::getId, rentOrder.getId());
        this.update(rentOrderLambdaUpdateWrapper);

        deviceBikeService.update(new LambdaUpdateWrapper<EbDeviceBike>()
                .set(EbDeviceBike::getUseStatus, BikeUseStatusEnum.RIDE.getCode())
                .set(EbDeviceBike::getUsePerson, UserTypeEnum.MEMBER.getCode())
                .set(EbDeviceBike::getLastRideTime, DateUtil.date())
                .set(EbDeviceBike::getLeaveAreaTime, null) // 重置下，防止有问题
                .eq(EbDeviceBike::getId, deviceBike.getId()));

        messageInfoService.addSys(memberPay.getMemberId(), MessageChannelEnum.SYS,
                "尊敬的用户，您于 "  + DateUtil.now() + " 购买租赁套餐"+rentCombo.getName()+"续租订单成功，支付" + memberPay.getMoney().doubleValue() + "元，感谢您的支持与信任！",
                null, MessageBusinessTypeEnum.RENT, null);
    }

    @Override
    @Transactional
    public void returnOrder(RentReturnBikeForm form, Boolean isSys) {
        // 租赁中订单
        List<EbRentOrder> rentOrders = this.getByBike(form.getBikeNo());
        if(rentOrders == null || rentOrders.size() <= 0) return;
        RentOrderVo rentOrder = this.getComboRunning(rentOrders.get(0).getMemberId());
        EbRentCombo rentCombo = rentComboService.getById(rentOrder.getComboId());
        if(rentCombo == null) return;

        Date returnTime = rentOrder.getOrderEndTime();
        if(rentCombo.getMaxTimeout() != null){
            returnTime = DateUtil.offsetMinute(rentOrder.getEndTime(), rentCombo.getMaxTimeout());
        }
        if(DateUtil.date().getTime() < returnTime.getTime()) return;
        for(EbRentOrder ebRentOrder : rentOrders) {
            this.endOrder(ebRentOrder, form.getAgentUser(), form.getUserType(), isSys);
        }

        // 违约单生成
        rentPenaltyService.rentPenalty(this.getById(rentOrder.getId()), deviceBikeService.getById(rentOrder.getBikeId()), true);
    }

    @Override
    @Transactional
    public void rentOrderPaySuccess(String payNo, String channelNo) {
        //支付信息
        EbMemberPay memberPay = memberPayService.getByNo(payNo);
        Assert.notNull(memberPay, "支付信息不存在");

        LambdaUpdateWrapper<EbMemberPay> memberPayLambdaUpdateWrapper = new LambdaUpdateWrapper<EbMemberPay>()
                .set(EbMemberPay::getChannelNo, channelNo)
                .set(EbMemberPay::getStatus, MemberPayStatusEnum.PAID.getCode())
                .eq(EbMemberPay::getId, memberPay.getId());
        AgentInfo agentInfo = agentCacheService.getAgent(memberPay.getAgentId().toString());
        // 手续费比例
        BigDecimal feeRatio = BigDecimal.ZERO;
        // 手续费金额
        BigDecimal feeMoney = BigDecimal.ZERO;
        // 处理微信/支付宝 支付手续费
        if(agentInfo != null) {
            if (PayChannelEnum.WXPAY.getCode().equals(memberPay.getPayChannel()) && agentInfo.getWxFeeRatio() != null) {
                feeRatio = agentInfo.getWxFeeRatio();
                feeMoney = agentInfo.getWxFeeRatio().multiply((memberPay.getMoney() == null? BigDecimal.ZERO : memberPay.getMoney())).setScale(2, BigDecimal.ROUND_HALF_UP);
            } else if (PayChannelEnum.ALIPAY.getCode().equals(memberPay.getPayChannel()) && agentInfo.getAliFeeRatio() != null) {
                feeMoney = agentInfo.getAliFeeRatio().multiply((memberPay.getMoney() == null? BigDecimal.ZERO : memberPay.getMoney())).setScale(2, BigDecimal.ROUND_HALF_UP);
                feeRatio = agentInfo.getAliFeeRatio();
            }
        }
        memberPayLambdaUpdateWrapper.set(EbMemberPay::getFeeRatio, feeRatio)
                .set(EbMemberPay::getFeeMoney, feeMoney);
        memberPayService.update(memberPayLambdaUpdateWrapper);

        MemberMoneyBusinessTypeEnum moneyBusinessTypeEnum = null;
        if(memberPay.getBusinessType().equals(MemberPayBusinessTypeEnum.RENT_PENALTY_PAY.getCode())){
            log.info("租赁违约金支付成功通知");
            this.penaltyPaySuccess(memberPay);
            moneyBusinessTypeEnum = MemberMoneyBusinessTypeEnum.RENT_PAY_PENALTY;
        }else if(memberPay.getBusinessType().equals(MemberPayBusinessTypeEnum.RENT_ORDER_PAY.getCode())){
            log.info("购买租赁套餐支付成功通知");
            this.rentPaySuccess(memberPay);
            moneyBusinessTypeEnum = MemberMoneyBusinessTypeEnum.RENT_COMBO;
        }else {
            log.error("租赁支付通知业务类型异常");
        }

        if (memberPay.getPayChannel().equals(PayChannelEnum.WALLET.getCode())) {
            BigDecimal payChargeMoney = memberPay.getMoney();
            memberWalletService.updateBalanceForBoth(memberPay.getAreaId(), memberPay.getMemberId(), payChargeMoney, BigDecimal.ZERO, moneyBusinessTypeEnum, memberPay.getBusinessId(), MemberMoneyOperationTypeEnum.USER);
        }else if(PayChannelEnum.WXPAY.getCode().equals(memberPay.getPayChannel()) || PayChannelEnum.ALIPAY.getCode().equals(memberPay.getPayChannel())){
            memberMoneyService.createPay(memberPay.getAreaId(), memberPay.getMemberId(), moneyBusinessTypeEnum, memberPay.getBusinessId(), MemberMoneyOperationTypeEnum.USER, memberPay.getMoney());
        }
    }

    @Override
    public void orderHandleCommand(BikeCommandNotify bikeCommandNotify) {
        log.info("租赁订单命令通知参数:{}", JSONObject.toJSONString(bikeCommandNotify));
        EbDeviceBike deviceBike = deviceBikeService.getById(bikeCommandNotify.getBikeId());
        if(deviceBike == null) return;
        List<EbRentOrder> rentOrders = this.getByBike(deviceBike.getBikeNo());
        if(ArrayUtil.isAllEmpty(rentOrders)) return;
        EbRentOrder rentOrder = rentOrders.get(0);
        EbRentOrder runningRentOrder = this.getComboRunning(rentOrder.getMemberId());
        if(runningRentOrder == null) return;
        EbRideCommand initCommand = rideCommandService.getCommand(runningRentOrder.getId(),bikeCommandNotify.getCommand(), RideCommandStatusEnum.INIT, RideCommandTypeEnum.RENT);
        if(initCommand == null) return;
        if (DateUtil.between(initCommand.getCreateTime(), new Date(), DateUnit.SECOND) > 2000) {
            rideCommandService.failCommand(initCommand.getId(), "指令初始化超时");
            return;
        }
        if (bikeCommandNotify.getCommand().equals(DeviceCommandEnum.CLOSE_LOCK.getType())) {
            for(EbRentOrder ebRentOrder : rentOrders) {
                rideCommandService.orderCloseCommand(deviceBike, ebRentOrder, initCommand);
            }
            // 违约单生成
            rentPenaltyService.rentPenalty(runningRentOrder, deviceBike, true);
        }
        // 结束订单指令
        rideCommandService.endCommand(initCommand);

        try {
            // 强制更新车辆标记
            iotBikeClient.updateBikeSysTags(initCommand.getBikeId());
        } catch (Exception e) {
            log.error("iotBikeClient.updateBikeSysTags error", e);
        }
    }

    private void rentPaySuccess(EbMemberPay memberPay){
        // 套餐信息
        EbRentCombo ebRentCombo = rentComboService.getById(memberPay.getBusinessId());
        Assert.notNull(ebRentCombo, "识别不到租赁套餐");

        // 生成租赁套餐订单
        this.createRecord(memberPay.getMemberId(), memberPay.getId(), memberPay.getPayNo(), memberPay.getAreaId(), memberPay.getMoney(), ebRentCombo);

        messageInfoService.addSys(memberPay.getMemberId(), MessageChannelEnum.SYS,
                "尊敬的用户，您于 "  + DateUtil.now() + " 购买租赁套餐"+ebRentCombo.getName()+"成功，支付" + memberPay.getMoney().doubleValue() + "元，感谢您的支持与信任！",
                null, MessageBusinessTypeEnum.RENT, null);
    }

    private void penaltyPaySuccess(EbMemberPay memberPay) {
        Assert.isTrue(MemberPayBusinessTypeEnum.RENT_PENALTY_PAY.getCode().equals(memberPay.getBusinessType()), "业务类型错误");

        EbRentPenalty rentPenalty = rentPenaltyService.getByPayId(memberPay.getId());
        Assert.notNull(rentPenalty, "租赁罚金信息不存在");

        rentPenaltyService.update(new LambdaUpdateWrapper<EbRentPenalty>()
                .set(EbRentPenalty::getStatus, RentPenaltyStatusEnum.FINISH_PAY.getCode())
                .set(EbRentPenalty::getPayTime, DateUtil.date())
                .eq(EbRentPenalty::getId, rentPenalty.getId()));


        messageInfoService.addSys(memberPay.getMemberId(), MessageChannelEnum.SYS,
                "尊敬的用户，您于 "  + DateUtil.now() + " 支付租赁违约金成功" + memberPay.getMoney().doubleValue() + "元，感谢您的支持与信任！",
                null, MessageBusinessTypeEnum.RENT, null);
    }

    @Override
    @Transactional
    public void endOrder(RentEndOrderForm form, Boolean isSys) {
        EbRentOrder rentOrder = this.getById(form.getOrderId());
        if(rentOrder == null || StrUtil.isBlank(rentOrder.getBikeNo())) return;

        List<EbRentOrder> ebRentOrders = this.getByBike(rentOrder.getBikeNo());
        for(EbRentOrder ebRentOrder : ebRentOrders) {
            this.endOrder(ebRentOrder, form.getAgentUser(), form.getUserType(), isSys);
        }
    }

    @Override
    @Transactional
    public void rentRefund(RentRefundForm form) {
        //支付信息
        EbMemberPay memberPay = memberPayService.getById(form.getPayId());
        Assert.notNull(memberPay, "支付信息不存在");
        Assert.isTrue(MemberPayBusinessTypeEnum.RENT_ORDER_PAY.getCode().equals(memberPay.getBusinessType())
                || MemberPayBusinessTypeEnum.RENT_PENALTY_PAY.getCode().equals(memberPay.getBusinessType()), "业务类型错误");
        Assert.isTrue(MemberPayStatusEnum.PAID.getCode().equals(memberPay.getStatus()), "支付记录不支持退款");

        String reason = "";
        RefundBusinessTypeEnum businessTypeEnum = null;
        if(form.getRefundType().equals(RentRefundTypeEnum.RENT_MONEY.getCode())) {
            // 订单信息
            EbRentOrder rentOrder = this.getById(form.getOrderId());
            Assert.notNull(rentOrder, "订单信息不存在");
            Assert.isTrue(RentOrderStatusEnum.FINISH.getCode().equals(rentOrder.getStatus()) || RentOrderStatusEnum.BIKE.getCode().equals(rentOrder.getStatus()), "该订单不支持执行退款");
            BigDecimal realRefundMoney = form.getRefundMoney().add((rentOrder.getRefundMoney() == null ? BigDecimal.ZERO : rentOrder.getRefundMoney()));
            Assert.isTrue(realRefundMoney.compareTo(rentOrder.getPayMoney()) <= 0, "租赁订单退款金额超出");
            reason = "租赁订单退款";
            businessTypeEnum = RefundBusinessTypeEnum.RENT;
        }else if(form.getRefundType().equals(RentRefundTypeEnum.CONTRACT_MONEY.getCode())){
            // 违约金信息
            EbRentPenalty rentPenalty = rentPenaltyService.getByOrderId(form.getOrderId());
            Assert.notNull(rentPenalty, "违约金信息不存在");
            Assert.isTrue(rentPenalty.getStatus().equals(RentPenaltyStatusEnum.FINISH_PAY.getCode()), "该订单不支持违约金退款");
            BigDecimal realRefundMoney = form.getRefundMoney().add((memberPay.getRefundMoney() == null ? BigDecimal.ZERO : memberPay.getRefundMoney()));
            Assert.isTrue(realRefundMoney.compareTo(rentPenalty.getPayMoney()) <= 0, "违约退款金额超出");
            reason = "租赁违约金额退款";
            businessTypeEnum = RefundBusinessTypeEnum.RENT_PENALTY;
        }else{
            throw new BadResponseException("不支持的退款类型");
        }

        String refundRedisKey = redisKey.concat("ORDER:REFUND:").concat(form.getOrderId().toString());
        if(redisService.hasKey(refundRedisKey)){
            throw new BadResponseException("请不要重复执行");
        }
        redisService.set(refundRedisKey, form.getOrderId(), 3);

        AgentInfo agentInfo = LocalMapUtil.getAgentInfo();
        String notifyUrl = (SpringContextUtil.isDev() ? "https://test.chengmandian.com.cn" : "https://chengmandian.com.cn" ) + "/api/v1/bikeuser/notify/rent";
        try {
            JSONObject dataJson = new JSONObject();
            dataJson.put("rent_refund_type", form.getRefundType());

            if (memberPay.getPayChannel().equals(PayChannelEnum.WALLET.getCode())) {
                // 生成退款支付记录
                EbRefundInfo ebRefundInfo = refundInfoService.createRefund(memberPay.getAreaId(), memberPay.getMemberId(), memberPay.getId(), memberPay.getId(), memberPay.getFeeRatio(), form.getRefundMoney(), businessTypeEnum, RefundChannelEnum.MONEY, form.getRefundReason(), form.getLoginUser(), dataJson.toJSONString());
                // memberWalletService.refundMoney(memberPay.getMemberId(), form.getRefundMoney(), BigDecimal.ZERO);
                this.rentRefundSuccess(ebRefundInfo, memberPay.getPayNo());
            } else if (memberPay.getPayChannel().equals(PayChannelEnum.WXPAY.getCode())) {
                // 生成退款支付记录
                EbRefundInfo ebRefundInfo = refundInfoService.createRefund(memberPay.getAreaId(), memberPay.getMemberId(), memberPay.getId(), memberPay.getId(), memberPay.getFeeRatio(), form.getRefundMoney(), businessTypeEnum, RefundChannelEnum.WX, form.getRefundReason(), form.getLoginUser(), dataJson.toJSONString());
                EbMemberInfo ebMemberInfo = memberInfoService.getById(memberPay.getMemberId());
                EbAgentInfo info = agentInfoService.getById(agentInfo.getId());
                if (info.getPayAccountId() != null) {
                    EbPayAccount payAccount = payAccountService.getPayAccount(info.getPayAccountId(), memberPay.getMemberId());
                    if (payAccount != null) {
                        BikeRefundForm refundForm = new BikeRefundForm();
                        refundForm.setBusinessType(businessTypeEnum);
                        refundForm.setMemberPayId(memberPay.getId());
                        refundForm.setMoney(ebRefundInfo.getMoney());
                        refundForm.setRefundNo(ebRefundInfo.getRefundNo());
                        refundForm.setAlipayUserId(ebMemberInfo.getAlipayUserId());
                        refundForm.setAlipayOpenId(ebMemberInfo.getAlipayOpenId());
                        AjaxResult result = payClient.refund(memberPay.getAgentId(), refundForm);
                        Assert.isTrue(result.isSuccess(), result.getMessage());
                        return;
                    }
                }
                try {
                    WxPayUtil.refund(
                            agentInfo.getWxMchId(),
                            ebRefundInfo.getRefundNo(),
                            memberPay.getPayNo(),
                            reason,
                            ebRefundInfo.getMoney(),
                            memberPay.getMoney(),
                            agentInfo.getWxKeyPath(),
                            agentInfo.getWxCertPath(),
                            notifyUrl + "/wx/rent/refund/" + LocalMapUtil.getAgentInfo().getId());
                } catch (Exception ex) {
                    log.error("微信退款失败", ex);
                    throw new BadResponseException("微信退款失败:" + ex.getMessage());
                }
            } else if (memberPay.getPayChannel().equals(PayChannelEnum.ALIPAY.getCode())) {
                // 生成退款支付记录
                EbRefundInfo ebRefundInfo = refundInfoService.createRefund(memberPay.getAreaId(), memberPay.getMemberId(), memberPay.getId(), memberPay.getId(), memberPay.getFeeRatio(), form.getRefundMoney(), businessTypeEnum, RefundChannelEnum.ALI, form.getRefundReason(), form.getLoginUser(), dataJson.toJSONString());
                EbMemberInfo ebMemberInfo = memberInfoService.getById(memberPay.getMemberId());
                EbAgentInfo info = agentInfoService.getById(agentInfo.getId());
                if (info.getPayAccountId() != null) {
                    EbPayAccount payAccount = payAccountService.getPayAccount(info.getPayAccountId(), memberPay.getMemberId());
                    if (payAccount != null) {
                        BikeRefundForm refundForm = new BikeRefundForm();
                        refundForm.setBusinessType(businessTypeEnum);
                        refundForm.setMemberPayId(memberPay.getId());
                        refundForm.setMoney(ebRefundInfo.getMoney());
                        refundForm.setRefundNo(ebRefundInfo.getRefundNo());
                        refundForm.setAlipayUserId(ebMemberInfo.getAlipayUserId());
                        refundForm.setAlipayOpenId(ebMemberInfo.getAlipayOpenId());
                        AjaxResult result = payClient.refund(memberPay.getAgentId(), refundForm);
                        Assert.isTrue(result.isSuccess(), result.getMessage());
                        return;
                    }
                }
                try {
                    Map<String, String> res = AliPayUtil.getTradeRefundRequestParam(
                            agentInfo.getAliMiniAppid(),
                            ebMemberInfo.getAlipayUserId(),
                            ebMemberInfo.getAlipayOpenId(),
                            reason,
                            memberPay.getPayNo(),
                            ebRefundInfo.getRefundNo(),
                            ebRefundInfo.getMoney(),
                            agentInfo.getAliPayPrivateKey(),
                            agentInfo.getAliPayCertPath(),
                            agentInfo.getAliPayPublicCertPath(),
                            agentInfo.getAliPayRootCertPath());
                    ebRefundInfo.setChannelNo(res.get("trade_no"));
                    this.rentRefundSuccess(ebRefundInfo, memberPay.getPayNo());
                } catch (Exception ex) {
                    log.error("支付宝退款失败", ex);
                    throw new BadResponseException("支付宝退款失败:" + ex.getMessage());
                }
            }
        }catch (Exception ex){
            ex.printStackTrace();
            throw new BadResponseException(ex.getMessage());
        }

    }

    @Override
    public void rentOrderCloseLock(EbRentOrder rentOrder, EbDeviceBike deviceBike) {
        deviceBikeService.update(new LambdaUpdateWrapper<EbDeviceBike>()
                .set(EbDeviceBike::getUseStatus, BikeUseStatusEnum.IDLE.getCode())
                .set(EbDeviceBike::getUsePerson, null)
                .eq(EbDeviceBike::getId, deviceBike.getId()));

        LambdaUpdateWrapper<EbRentOrder> updateWrapper = new LambdaUpdateWrapper<>();
        // 站点
        if(deviceBike.getStationId() != null) {
            EbOperationStation operationStation = operationStationService.getById(deviceBike.getStationId());
            if(operationStation != null && operationStation.getId() != null){
                updateWrapper.set(EbRentOrder::getEndStationName, operationStation.getName());
                updateWrapper.set(EbRentOrder::getEndStationId, operationStation.getId());
            }
        }
        updateWrapper.set(EbRentOrder::getRealEndTime, DateUtil.date());
        //还车时长
        Long useTime = DateUtil.between(rentOrder.getStartTime(), DateUtil.date(), DateUnit.SECOND);
        updateWrapper.set(EbRentOrder::getUseTime, useTime);
        updateWrapper.set(EbRentOrder::getStatus, RentOrderStatusEnum.FINISH.getCode());
        updateWrapper.set(EbRentOrder::getEndLat, deviceBike.getLat());
        updateWrapper.set(EbRentOrder::getEndLng, deviceBike.getLng());
        updateWrapper.eq(EbRentOrder::getId, rentOrder.getId());
        this.update(updateWrapper);
    }

    @Override
    @Transactional
    public void rentRefundSuccess(EbRefundInfo ebRefundInfo, String payNo) {
        JSONObject dataJson = JSONObject.parseObject(ebRefundInfo.getData());
        log.info("退款信息DATA:{}", dataJson);
        Integer refundType = dataJson.getInteger("rent_refund_type");
        // 支付信息
        EbMemberPay memberPay = memberPayService.getByNo(payNo);
        Assert.notNull(memberPay, "无支付信息");
        Assert.isTrue(MemberPayStatusEnum.PAID.getCode().equals(memberPay.getStatus()), "支付记录不支持退款");

        BigDecimal refundMoney = ebRefundInfo.getMoney().add((memberPay.getRefundMoney() == null? BigDecimal.ZERO :memberPay.getRefundMoney()));
        MemberPayStatusEnum memberPayStatusEnum = MemberPayStatusEnum.PAID;
        if(refundMoney.compareTo(memberPay.getMoney()) >=0){
            memberPayStatusEnum = MemberPayStatusEnum.REFUND;
        }
        // 支付记录退款
        memberPayService.update(new LambdaUpdateWrapper<EbMemberPay>()
                .set(EbMemberPay::getRefundTime, DateUtil.date())
                .set(EbMemberPay::getRefundMoney, refundMoney)
                .set(EbMemberPay::getChannelRefundNo, ebRefundInfo.getRefundNo())
                .set(EbMemberPay::getStatus, memberPayStatusEnum.getCode())
                .eq(EbMemberPay::getId, memberPay.getId()));

        // 退款记录
        refundInfoService.update(new LambdaUpdateWrapper<EbRefundInfo>()
                .set(EbRefundInfo::getStatus,RefundStatusEnum.REFUND_OK.getCode())
                .set(EbRefundInfo::getCompleteTime,new Date())
                .set(EbRefundInfo::getRefundMoney,ebRefundInfo.getMoney())
                .set(EbRefundInfo::getChannelNo,ebRefundInfo.getChannelNo())
                .eq(EbRefundInfo::getId,ebRefundInfo.getId()));

        if(dataJson != null && !dataJson.isEmpty()) {
            // 租赁金额
            if (refundType.equals(RentRefundTypeEnum.RENT_MONEY.getCode())) {
                EbRentOrder rentOrder = this.getByPayId(memberPay.getId());
                log.info("租赁订单退款:{}", rentOrder.getOrderNo());
                RentOrderStatusEnum statusEnum = RentOrderStatusEnum.FINISH;
                if (refundMoney.compareTo(rentOrder.getPayMoney()) >= 0) {
                    statusEnum = RentOrderStatusEnum.REFUND;
                }
                LambdaUpdateWrapper<EbRentOrder> orderLambdaUpdateWrapper = new LambdaUpdateWrapper<EbRentOrder>();
                orderLambdaUpdateWrapper.set(EbRentOrder::getStatus, statusEnum.getCode());
                orderLambdaUpdateWrapper.set(EbRentOrder::getRefundMoney, refundMoney);
                orderLambdaUpdateWrapper.eq(EbRentOrder::getId, rentOrder.getId());
                this.update(orderLambdaUpdateWrapper);
            } else
                // 违约金额
                if (refundType.equals(RentRefundTypeEnum.CONTRACT_MONEY.getCode())) {
                    EbRentPenalty rentPenalty = rentPenaltyService.getByPayId(memberPay.getId());
                    Assert.notNull(rentPenalty, "缺少违约金信息");
                    log.info("租赁订单违约金额退款:{}", rentPenalty.getPenaltyNo());
                    LambdaUpdateWrapper<EbRentPenalty> penaltyLambdaUpdateWrapper = new LambdaUpdateWrapper<EbRentPenalty>();
                    penaltyLambdaUpdateWrapper.set(EbRentPenalty::getStatus, RentPenaltyStatusEnum.REFUND.getCode());
                    penaltyLambdaUpdateWrapper.eq(EbRentPenalty::getId, rentPenalty.getId());
                    rentPenaltyService.update(penaltyLambdaUpdateWrapper);
                }
        }

        messageInfoService.addSys(memberPay.getMemberId(), MessageChannelEnum.SYS,
                "尊敬的用户，您于 "  + DateUtil.now() + " 退款成功" + ebRefundInfo.getMoney().doubleValue() + "元，感谢您的支持与信任！",
                null, MessageBusinessTypeEnum.RENT, null);
    }

    private  void endOrder(EbRentOrder rentOrder, AgentUser agentUser, Integer userType, Boolean isSys){
        Assert.notNull(rentOrder, "订单不存在");
        Assert.isTrue(RentOrderStatusEnum.RENT.getCode().equals(rentOrder.getStatus()), "订单不支持该操作");

        EbDeviceBike ebDeviceBike = deviceBikeService.getById(rentOrder.getBikeId());
        Assert.notNull(ebDeviceBike, "车辆信息不存在");
        Assert.isTrue(StrUtil.isNotBlank(ebDeviceBike.getControlNo()), "车辆未绑定中控");
        EbDeviceBike deviceBike = deviceBikeService.getByNo(rentOrder.getBikeNo());

        String endRedisKey = redisKey.concat("END:ORDER:").concat(rentOrder.getId().toString());
        if(redisService.hasKey(endRedisKey)) {
            if(isSys) {
                this.rentOrderCloseLock(rentOrder, deviceBike);
            }
            return;
        }
        redisService.set(endRedisKey, rentOrder.getId(), 10);

        // 系统关锁
        if(isSys || (deviceBike.getLockStatus() != null && !deviceBike.getLockStatus().equals(CommonConstant.ONE))){
            this.rentOrderCloseLock(rentOrder, deviceBike);
        }

        // 订单车辆关锁
        String lockRedisKey = redisKey.concat("BIKE:COMMAND:LOCK:").concat(deviceBike.getId().toString());
        if(redisService.hasKey(lockRedisKey)) return;
        redisService.set(lockRedisKey, deviceBike.getId(), 10);
        if(deviceBike.getLockStatus() != null && deviceBike.getLockStatus().equals(CommonConstant.ONE)) {
            rideCommandService.addCommand(this.getById(rentOrder.getId()), DeviceCommandEnum.CLOSE_LOCK, userType, agentUser.getId(), agentUser.getName(), DateUtil.date());
        }
    }
}
